package org.ala.tiktools.tools.kv;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * map帮助类
 *
 * @author ala
 * @date 2025-02-19 22:31
 */
public class Maps {

    /**
     *  构建空Map
     */
    public static <K,V> Map<K,V> empty() {return new HashMap<>();}

    /**
     *  构建map
     */
    @SuppressWarnings("unchecked")
	public static <K,V> Map<K,V> build(KV<K,V>... kvs) {
        Map<K,V> map = new HashMap<>();
        for (KV<K, V> kv : kvs) {
            map.put(kv.k, kv.v);
        }
        return map;
    }
    /**
     *  判断map是否为空
     */
    @SuppressWarnings("rawtypes")
	public static boolean isEmpty(Map map) {
        return map == null || map.isEmpty();
    }
    /**
     *  原key转换
     */
    public static <K,V,E> Map<K,V> convert(Map<K,E> map, Function<E,V> convert) {
        return map.entrySet().stream().collect(Collectors.toMap(
                e -> e.getKey(),
                e -> convert.apply(e.getValue()),
                (o,n) -> n
        ));
    }
    /**
     *  原key分组
     */
    public static <K,V> void reGroup(Map<K,List<V>> map, Map<K,List<V>> append) {
        append.forEach((k, v) -> {
            map.computeIfAbsent(k, _k -> new ArrayList<>()).addAll(v);
        });
    }
    /**
     *  原key分组
     */
    public static <K,V> void appendGroup(Map<K,List<V>> map, Map<K,V> append) {
        if (Maps.isEmpty(append)) {return;}
        append.forEach((k, v) -> {
            map.computeIfAbsent(k, _k -> new ArrayList<>()).add(v);
        });
    }
    /**
     *  原key分组
     */
    public static <K,V,E> Map<K,V> group(List<E> es, Function<E,K> key, Callable<V> copy, BiConsumer<E,V> setter) {
        Map<K,V> res = new HashMap<>();
        es.forEach(e -> {
            V v = res.computeIfAbsent(
                    key.apply(e),
                    k -> {
                        try {
                            return copy.call();
                        } catch (Exception ex) {
                            throw new RuntimeException(ex);
                        }
                    });
            setter.accept(e, v);
        });
        return res;
    }

}
